from flask_restful import Resource
from flask import g
from flask import request
from flask_restful.reqparse import RequestParser
from models.news import Channel,UserChannel,Article
from cache.channel import AllChannelCache,UserChannelCache,UserDefaultChannelsCache
from toutiao.utils.parsers import check_channel_id
from toutiao.utils.decorators import Loginrequired
from toutiao import db

#获取文章列表GET /app/v1_0/articles?channel_id=xxx&timestamp=xxx&with_top=xxx
class IndexResource(Resource):

    def get(self):
        '''
        接收数据(查询字符串参数　request.args)
        验证数据
        查询数据，对象列表转字典列表
        返回相应
        :return:
        '''
        parser = RequestParser()
        parser.add_argument('channel_id',location = 'args',required=True,type=check_channel_id)
        args = parser.parse_args()
        channel_id = args.get('channel_id')
        #推荐里没有内容，改成频道１实现效果
        # if int(channel_id) == 0:
        #     channel_id = 1
        #获取到查询字符串的channel_id后查询文章模型
        articles = Article.query.filter(Article.channel_id==channel_id,
                                        Article.status==Article.STATUS.APPROVED).all()
        #对象列表转字典列表
        data_list = []
        for item in articles:
            data_list.append({
                "art_id": item.id,
                "title": item.title,
                "aut_id": item.user.id,
                "pubdate": item.ctime.strftime('%Y-%m-%d %H:%M:%S'),
                "aut_name": item.user.name,
                "comm_count": item.comment_count,
                "is_top": False,
                'cover': item.cover,
            })
            # pre_timestamp不为0会一直获取数据
        return {'pre_timestamp':0,'results':data_list}

#定义字段
from flask_restful import fields,marshal,marshal_with
all_channel_fields = {
    'id':fields.Integer,
    'name':fields.String
}
#获取所有频道
class AllChannelResource(Resource):

    # @marshal_with(all_channel_fields)  #方法一：用装饰器方法时return channels
    def get(self):
        '''
        查询模型，获取对象列表
        对象列表转字典列表
        返回相应
        :return:
        '''
        #方法二：使用marshal
        # channels = Channel.query.filter(Channel.is_visible==True).order_by(Channel.sequence.asc()).all()
        # return marshal(channels,all_channel_fields,envelope='channels')

        #使用缓存直接调用方法获取
        return AllChannelCache.get()


#用户关注频道
class UserChannelResource(Resource):
    method_decorators = {'put':[Loginrequired]}
    '''
    1.先获取用户的信息
    2.如果是登陆用户，我们需要查询 登陆用户的关注频道
            对象列表转换为字典列表
      如果是未登陆用户，我们需要查询 默认的频道
            对象列表转换为字典列表
    3.返回相应

    '''
    #方式一：未使用缓存，直接视图中查询返回
    # def get(self):
    #     user_id = g.user_id
    #     if user_id:
    #         #登陆用户进行数据查询
    #         channels = UserChannel.query.filter(UserChannel.user_id==user_id,
    #                                             UserChannel.is_deleted==False).order_by(UserChannel.sequence).all()
    #     else:
    #         #未登录用户返回默认频道数据
    #         channels = Channel.query.filter(Channel.is_default == True,
    #                                         Channel.is_visible == True).order_by(Channel.sequence,Channel.id).all()
    #     #根据需求，推荐列表必须存在
    #     data_list = [{
    #         'id':0,
    #         'name':'推荐'
    #     }]
    #     #已登录和未登录查询的用户不同，所以name的遍历方法不同
    #     # channel为UserChannel模型中（一对多）一方的db.relationship字段
    #     for channel in channels:
    #         data_list.append({
    #             'id':channel.id,
    #             'name':channel.channel.name if user_id else channel.name
    #         })
    #
    #     return {'channels':data_list}

    #方式二：使用缓存查询（抽取查询代码，保留主逻辑，缓存查询速度快）
    def get(self):
        user_id = g.user_id

        #两种缓存添加方式
        if user_id:
            # 已登录(需要传参)实例调方法class(user_id).get()
            data = UserChannelCache(user_id).get()
        else:
            # 未登录用户(无需传参)类调方法class.get()
            data = UserDefaultChannelsCache.get()

        data_list = [{
            'id': 0,
            'name': '推荐'
        }] + data

        return {"channels": data_list}

    #修改用户关注频道
    def put(self):
        '''
        只有登录用户可以修改
        接收数据，channels:[{'channel_id':xx,'seq':1},{'channel_id':xx,'seq':2}]
        校验数据,查询用户关注的所有频道，设置is_delete=True
                遍历前端数据，查找channel_id更新is_delete,sequence
                没有更新成功的说明没有查到数据，则插入到数据库
        将接收的数据返回，（主要修改数据库以及缓存，所以数据直接返回即可）
        注：缓存会影响查询，所以每次修改都需要删除缓存
        :return:
        '''
        #获取数据
        user_id = g.user_id
        channel_list = request.json.get('channels')
        #查询用户关注的所有频道，设置is_delete=True
        UserChannel.query.filter(UserChannel.is_deleted==False,
                                 UserChannel.user_id==user_id).update({'is_deleted':True})

        #遍历前端数据
        for channel in channel_list:
            update_data = {
                'is_deleted':False,
                'sequence':channel.get('seq')
            }
        #更新成功返回操作的数据条数
        flag = UserChannel.query.filter(UserChannel.channel_id==channel.get('id'),
                                 UserChannel.user_id==g.user_id).update(update_data)

        #没有更新成功的插入数据
        if flag == 0:
            userchannel = UserChannel()
            userchannel.user_id = g.user_id
            userchannel.channel_id = channel.get('id')
            userchannel.is_deleted = False
            userchannel.sequence = channel.get('seq')
            db.session.add(userchannel)

        #删除缓存
        UserChannelCache(g.user_id).clear()

        return {'channels':channel_list}